package com.ebeitech.library.util;

import android.content.ContentUris;
import android.content.Context;
import android.database.Cursor;
import android.net.Uri;
import android.os.Build;
import android.os.Environment;
import android.provider.MediaStore;
import android.util.Log;

import java.io.BufferedInputStream;
import java.io.BufferedOutputStream;
import java.io.ByteArrayOutputStream;
import java.io.Closeable;
import java.io.File;
import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.io.RandomAccessFile;
import java.lang.reflect.Method;
import java.text.DecimalFormat;

/**
 * Created by alice on 2017/10/25.
 */
public class FileUtil {

	/**
	 * 根据指定的路径创建文件
	 *
	 * @param filepath
	 * @return
	 * @throws IOException
	 */
	public static File createFile(String filepath) throws IOException {
		int last_seperate = filepath.lastIndexOf("/") + 1;
		String path = filepath.substring(0, last_seperate);
		String name = filepath.substring(last_seperate);
		return createFile(path, name);
	}

	/**
	 * 由指定的路径和文件名创建文件
	 *
	 * @param path
	 * @param name
	 * @return
	 * @throws IOException
	 */
	public static File createFile(String path, String name) throws IOException {
		File folder = new File(path);
		if (!folder.exists()) {
			folder.mkdirs();
		}
		File file = new File(path + name);
		if (!file.exists()) {
			file.createNewFile();
		}
		return file;
	}

	/**
	 * 删除指定文件
	 *
	 * @param path
	 * @param name
	 */
	public static void deleteFile(String path, String name) {
		if (!fileExist(path, name)) {
			return;
		}
		File file = new File(path + name);
		file.delete();
	}

	/**
	 * 删除指定文件
	 *
	 * @param path
	 */
	public static void deleteFile(String path) {
		deleteFile(new File(path));
	}

	/**
	 * 删除指定文件或文件夹
	 *
	 * @param file
	 */
	public static void deleteFile(File file) {
		if (file.isDirectory()) {
			File[] files = file.listFiles();
			for (int i = 0; i < files.length; i++) {
				File f = files[i];
				deleteFile(f);
			}
			file.delete();//如要保留文件夹，只删除文件，请注释这行
		} else if (file.exists()) {
			file.delete();
		}

	}

	/**
	 * 判断文件是否存在
	 *
	 * @param path
	 * @param name
	 * @return
	 */
	public static boolean fileExist(String path, String name) {
		File file = new File(path + name);
		if (file.exists() & !file.isDirectory()) {
			return true;
		}
		return false;
	}
	/**
	 * 判断文件是否存在
	 *
	 * @param path
	 * @return
	 */
	public static boolean fileExist(String path) {
		File file = new File(path);
		if (file.exists()) {
			return true;
		}
		return false;
	}

	/**
	 * 拷贝文件
	 *
	 * @param srcPath
	 * @param srcName
	 * @param desPath
	 * @param desName
	 * @return boolean
	 */
	public static boolean copyFile(String srcPath, String srcName, String desPath, String desName) {
		if (!fileExist(srcPath, srcName)) {
			return false;
		}

		FileInputStream fis = null;
		BufferedInputStream bis = null;
		FileOutputStream fos = null;
		BufferedOutputStream bos = null;
		try {
			File inFile = new File(srcPath, srcName);
			File outFile = new File(desPath, desName);

			if (!fileExist(desPath, desName)) {
				createFile(desPath, desName);
			}

			fis = new FileInputStream(inFile);
			bis = new BufferedInputStream(fis);

			fos = new FileOutputStream(outFile);
			bos = new BufferedOutputStream(fos);

			byte[] buffer = new byte[1024 * 8];
			int len = -1;
			while ((len = fis.read(buffer)) != -1) {
				bos.write(buffer, 0, len);
			}
			bos.flush();
			return true;
		} catch (Exception e) {
			e.printStackTrace();
		} finally {
			closeStream(bis);
			closeStream(fis);
			closeStream(bos);
			closeStream(fos);
		}
		return false;
	}

	/**
	 * 拷贝文件
	 *
	 * @param srcPath
	 * @param desPath
	 * @return boolean
	 */
	public static boolean copyFile(String srcPath, String desPath) {
		if (!fileExist(srcPath)) {
			return false;
		}

		FileInputStream fis = null;
		BufferedInputStream bis = null;
		FileOutputStream fos = null;
		BufferedOutputStream bos = null;
		try {
			File inFile = new File(srcPath);
			File outFile = new File(desPath);

			if (!fileExist(desPath)) {
				createFile(desPath);
			}

			fis = new FileInputStream(inFile);
			bis = new BufferedInputStream(fis);

			fos = new FileOutputStream(outFile);
			bos = new BufferedOutputStream(fos);

			byte[] buffer = new byte[1024 * 8];
			int len = -1;
			while ((len = fis.read(buffer)) != -1) {
				bos.write(buffer, 0, len);
			}
			bos.flush();
			return true;
		} catch (Exception e) {
			e.printStackTrace();
		} finally {
			closeStream(bis);
			closeStream(fis);
			closeStream(bos);
			closeStream(fos);
		}
		return false;
	}

	/**
	 * Close outputStream
	 *
	 * @param stream
	 */
	public static void closeStream(Closeable stream) {
		if (stream != null) {
			try {
				stream.close();
				stream = null;
			} catch (IOException e) {
				Log.e("e",e.getMessage());
			} finally {
				if (stream != null) {
					try {
						stream.close();
					} catch (IOException e) {
						stream = null;
						Log.e("e",e.getMessage());
					}
					stream = null;
				}
			}
		}
	}

	/**
	 * 写入文件
	 *
	 * @param dataPath
	 * @param data
	 * @throws IOException
	 */
	public static synchronized void saveData(String dataPath, String data) throws IOException {
		File file = createFile(dataPath);
		RandomAccessFile raf = new RandomAccessFile(file, "rws");
		byte[] byteds = data.getBytes();
		raf.seek(file.length());
		raf.write(byteds);
		closeStream(raf);
	}

	/**
	 * 调用此方法自动计算指定文件或指定文件夹的大小
	 *
	 * @param filePath 文件路径
	 * @return 计算好的带B、KB、MB、GB的字符串
	 */
	public static long getFileSize(String filePath) {
		File file = new File(filePath);
		long blockSize = 0;
		try {
			if (file.isDirectory()) {
				blockSize = getFileSizeByDirectory(file);
			} else {
				blockSize = getFileSizeByFile(file);
			}
		} catch (Exception e) {
			e.printStackTrace();
			com.ebeitech.library.util.Log.e("获取文件大小失败!");
		}
		return blockSize;
	}

	/**
	 * 转换文件大小
	 *
	 * @param fileS
	 * @return
	 */
	public static String formatFileSize(long fileS) {
		DecimalFormat df = new DecimalFormat("#.00");
		String fileSizeString = "";
		String wrongSize = "0B";
		if (fileS == 0) {
			return wrongSize;
		}
		if (fileS < 1024) {
			fileSizeString = df.format((double) fileS) + "B";
		} else if (fileS < 1048576) {
			fileSizeString = df.format((double) fileS / 1024) + "KB";
		} else if (fileS < 1073741824) {
			fileSizeString = df.format((double) fileS / 1048576) + "MB";
		} else {
			fileSizeString = df.format((double) fileS / 1073741824) + "GB";
		}
		return fileSizeString;
	}

	/**
	 * 获取指定文件夹
	 *
	 * @param f
	 * @return
	 * @throws Exception
	 */
	private static long getFileSizeByDirectory(File f) throws Exception {
		long size = 0;
		File flist[] = f.listFiles();
		for (int i = 0; i < flist.length; i++) {
			if (flist[i].isDirectory()) {
				size = size + getFileSizeByDirectory(flist[i]);
			} else {
				size = size + getFileSizeByFile(flist[i]);
			}
		}
		return size;
	}

	/**
	 * 获取指定文件大小
	 *
	 * @param file
	 * @return
	 * @throws Exception
	 */
	private static long getFileSizeByFile(File file) throws Exception {
		long size = 0;
		if (file.exists()) {
			FileInputStream fis = null;
			fis = new FileInputStream(file);
			size = fis.available();
		} else {
			file.createNewFile();
			com.ebeitech.library.util.Log.e("获取文件大小不存在!");
		}
		return size;
	}

	/**
	 * 根据图片的Uri获取图片的绝对路径
	 *
	 * @param context
	 * @param uri
	 * @return
	 */
	public static String getPathByUrl(Context context, Uri uri) {
		String picPath ="";
		int sdkVersion = Integer.valueOf(Build.VERSION.SDK);
		if (sdkVersion >= 19) {  // 或者 android.os.Build.VERSION_CODES.KITKAT这个常量的值是19
			picPath = getPath_above19(context, uri);//5.0直接返回的是图片路径 Uri.getPath is ：  /document/image:46 ，5.0以下是一个和数据库有关的索引值
			// path_above19:/storage/emulated/0/girl.jpg 这里才是获取的图片的真实路径
		} else {
			picPath = getFilePath_below19(context, uri);
		}
		return picPath;
	}

	/**
	 * 获取小于api19时获取相册中图片真正的uri
	 * @param context
	 * @param uri
	 * @return
	 */
	private static String getFilePath_below19(Context context,Uri uri) {
		//这里开始的第二部分，获取图片的路径：低版本的是没问题的，但是sdk>19会获取不到
		String[] proj = {MediaStore.Images.Media.DATA};
		//好像是android多媒体数据库的封装接口，具体的看Android文档
		Cursor cursor = context.getContentResolver().query(uri, proj, null, null, null);
		//获得用户选择的图片的索引值
		int column_index = cursor.getColumnIndexOrThrow(MediaStore.Images.Media.DATA);
		//将光标移至开头 ，这个很重要，不小心很容易引起越界
		cursor.moveToFirst();
		//最后根据索引值获取图片路径   结果类似：/mnt/sdcard/DCIM/Camera/IMG_20151124_013332.jpg
		String path = cursor.getString(column_index);
		return path;
	}

	/**
	 * 获取大于api19时获取相册中图片真正的uri
	 * @param context
	 * @param uri
	 * @return
	 */
	private  static String getPath_above19(final Context context, final Uri uri) {
		final boolean isKitKat = Build.VERSION.SDK_INT >= Build.VERSION_CODES.KITKAT;
		// DocumentProvider
		boolean isDocumentUri = false;
		Class<?> docContract = null;
		try {
			docContract = Class.forName("android.provider.DocumentsContract");
			Method isDocUri = docContract.getDeclaredMethod(
					"isDocumentUri", Context.class, Uri.class);
			isDocumentUri = (Boolean) isDocUri.invoke(docContract, context, uri);
		} catch (Exception e) {
			// TODO: handle exception
		}
		if (isKitKat && isDocumentUri) {
			// ExternalStorageProvider
			String documentId = "";
			try {
				Method getDocumentId = docContract.getDeclaredMethod(
						"getDocumentId", Uri.class);
				documentId = (String) getDocumentId.invoke(docContract, uri);
			} catch (Exception e) {
				// TODO: handle exception
			}
			if (isExternalStorageDocument(uri)) {
				final String docId = documentId;
				final String[] split = docId.split(":");
				final String type = split[0];
				if ("primary".equalsIgnoreCase(type)) {
					return Environment.getExternalStorageDirectory() + "/" + split[1];
				}
			}
			// DownloadsProvider
			else if (isDownloadsDocument(uri)) {
				final String id = documentId;
				final Uri contentUri = ContentUris.withAppendedId(
						Uri.parse("content://downloads/public_downloads"), Long.valueOf(id));
				return getDataColumn(context, contentUri, null, null);
			}
			// MediaProvider
			else if (isMediaDocument(uri)) {
				final String docId = documentId;
				final String[] split = docId.split(":");
				final String type = split[0];
				Uri contentUri = null;
				if ("image".equals(type)) {
					contentUri = MediaStore.Images.Media.EXTERNAL_CONTENT_URI;
				} else if ("video".equals(type)) {
					contentUri = MediaStore.Video.Media.EXTERNAL_CONTENT_URI;
				} else if ("audio".equals(type)) {
					contentUri = MediaStore.Audio.Media.EXTERNAL_CONTENT_URI;
				}
				final String selection = "_id=?";
				final String[] selectionArgs = new String[]{
						split[1]
				};
				return getDataColumn(context, contentUri, selection, selectionArgs);
			}
		}
		// MediaStore (and general)
		else if ("content".equalsIgnoreCase(uri.getScheme())) {
			// Return the remote address
			if (isGooglePhotosUri(uri))
				return uri.getLastPathSegment();
			return getDataColumn(context, uri, null, null);
		}
		// File
		else if ("file".equalsIgnoreCase(uri.getScheme())) {
			return uri.getPath();
		}
		return null;
	}

	public static boolean isExternalStorageDocument(Uri uri) {
		return "com.android.externalstorage.documents".equals(uri.getAuthority());
	}

	public static boolean isDownloadsDocument(Uri uri) {
		return "com.android.providers.downloads.documents".equals(uri.getAuthority());
	}

	public static boolean isMediaDocument(Uri uri) {
		return "com.android.providers.media.documents".equals(uri.getAuthority());
	}

	public static boolean isGooglePhotosUri(Uri uri) {
		return "com.google.android.apps.photos.content".equals(uri.getAuthority());
	}

	public static String getDataColumn(Context context, Uri uri,
									   String selection, String[] selectionArgs) {
		Cursor cursor = null;
		final String column = "_data";
		final String[] projection = { column };
		try {
			cursor = context.getContentResolver().query(uri, projection,
					selection, selectionArgs, null);
			if (cursor != null && cursor.moveToFirst()) {
				final int index = cursor.getColumnIndexOrThrow(column);
				return cursor.getString(index);
			}
		} finally {
			if (cursor != null)
				cursor.close();
		}
		return null;
	}

	public static byte[] readInputStream(InputStream inStream)
			throws IOException {
		ByteArrayOutputStream baos = new ByteArrayOutputStream();
		byte[] buffer = new byte[1024];
		int len = 0;
		while ((len = inStream.read(buffer)) != -1) {
			baos.write(buffer, 0, len);

		}
		byte[] data = baos.toByteArray();// 网页的二进制数据
		baos.close();
		inStream.close();
		return data;
	}

}
